﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Circle.Domain.Interface.Service;
using Circle.Domain.Entity;
using Circle.Web.ViewModelsClient;
using System.Linq.Expressions;
using Circle.Web.ViewModels;
using Circle.Web.Drivers;
using Circle.Domain.Model;
using System.Data.Entity;
using Circle.Web.Drivers.Contract;
using System.Linq.Dynamic;
using Circle.Web.Application;
using LinqDynamicKit;
using Circle.Manager;
using Circle.Utility;
using Circle.Website.ViewModels;

namespace Circle.Web.Drivers
{
    public class TopicDriver : OwnerableEntityDriver<ContentTopic, TopicClientModel>, ITopicDriver 
    {

        private readonly ITopicService _topicService;
        private readonly ICommentService _commentService;
        private readonly ICommentDriver _commentDriver;

        public TopicDriver(ITopicService contentTopicService, ICommentService commentService, 
            ICommentDriver commentDriver)
            : base(contentTopicService)
        {
            _topicService = contentTopicService;
            _commentService = commentService;
            _commentDriver = commentDriver;
        }

        #region IConvertable

        public override TopicClientModel ToClient(ContentTopic entity, TopicClientModel cModel = null, string[] excludeProperties = null, bool serverStatus = true)
        {
            if (entity == null) return null;

            TopicClientModel topicClient = base.ToClient(entity, cModel, excludeProperties, serverStatus);

            topicClient.Title = entity.Title;
            topicClient.SubTitle = entity.SubTitle;
            topicClient.IsSticky = entity.IsLocked;
            topicClient.IsLocked = entity.IsLocked;
            topicClient.CreateTime = entity.CreateTime;
            topicClient.LastUpdateTime = entity.LastUpdateTime;
            topicClient.Thumbnail = entity.Thumbnail;


            if (excludeProperties==null || !excludeProperties.Contains("FirstComment"))
            {
                topicClient.FirstCommentId = entity.FirstComment.Id;
                topicClient.Content = entity.FirstComment.Content;
            }

            if (excludeProperties == null || !excludeProperties.Contains("Vote"))
            {
                if (topicClient.Vote == null) { topicClient.Vote = new VoteClientModel(); }

                topicClient.Vote.CommentId = entity.FirstComment.Id;
                topicClient.Vote.UserName = entity.UserName;
                topicClient.Vote.VoteUpCount = entity.FirstComment.VoteUpCount;
                topicClient.Vote.VoteDownCount = entity.FirstComment.VoteDownCount;
            }

            if (excludeProperties == null || !excludeProperties.Contains("Comments"))
            {
                if (topicClient.Comments == null) { topicClient.Comments = new List<CommentClientModel>(); }
                if (entity.Comments != null && entity.Comments.Count > 0)
                {
                    foreach (var comment in entity.Comments)
                    {
                        topicClient.Comments.Add(_commentDriver.ToClient(comment));
                    }
                }
            }

           

            return topicClient;
        }

        public override ContentTopic FromClient(ContentTopic m, TopicClientModel cModel, string[] includeProperties)
        {
            ContentTopic topic = base.FromClient(m, cModel, includeProperties);
            if (topic == null) return null;

            topic.Title = cModel.Title;
            topic.SubTitle = cModel.SubTitle;
            topic.FirstComment.Content = cModel.Content;
            topic.FirstComment.IsAttachedToTopic = true;
            topic.Thumbnail = cModel.Thumbnail;


            return topic;
    
        }
       

        #endregion

        public override OperationStatus Save(TopicClientModel cModel, string[] includeProperties = null, string[] excludeProperties = null)
        {
            return base.Save(cModel, new string[]{"FirstComment"}, new string[]{"Vote"});
        }

        //get topics on paging
        public PageListClient<TopicClientModel> PagingClientTopics(int pageSize, PageTopicFilterClient filter)
        {
            Expression<Func<ContentTopic, bool>> predicate = PredicateBuilder.True<ContentTopic>(); // null; // = x => x.IsVisible == false;

          
            var pageTopic = _topicService.Paging(filter.PageIndex, pageSize, filter.Sort, predicate);
            PageListClient<TopicClientModel> page = new PageListClient<TopicClientModel>(pageTopic);
            foreach (var topic in pageTopic)
            {
                page.Add(ToClient(topic, excludeProperties: new string[] { "Comments", "UploadPermission"}));
            }
         
            return page;
        }

        public PageListClient<TopicClientModel> PagingMyClientTopics(int pageIndex, int pageSize, string sort)
        {
            Expression<Func<ContentTopic, bool>> predicate = PredicateBuilder.True<ContentTopic>();
            predicate = predicate.And(x => x.UserId == SecurityManager.CurrentUser.UserId);
            predicate = predicate.Expand();

            var pageTopic = _topicService.Paging(pageIndex, pageSize, sort, predicate);
            PageListClient<TopicClientModel> page = new PageListClient<TopicClientModel>(pageTopic);
            foreach (var topic in pageTopic)
            {
                page.Add(ToClient(topic, excludeProperties: new string[] {"Comments", "UploadPermission"}));
            }

            return page;
        }

        public bool HasPermission(EntityPermission permission, ContentTopic contentTopic = null, Guid? threadId = null)
        {
            return _topicService.HasPermission(permission, contentTopic, threadId);
        }

        //get single topic with its posts on paging
        public TopicWithComments GetTopicWithComments(Guid topicId, int pageIndex, int CommentsPerPage)
        {

            TopicWithComments topicWithComments = new TopicWithComments();

            if (topicId == Guid.Empty) return null;
            Expression<Func<ContentComment, bool>> predicate = x => x.TopicId == topicId;
            topicWithComments.Comments = _commentService.Paging(pageIndex, CommentsPerPage, "CreateTime desc", predicate, new string[]{"Topic", "Topic.User", "Topic.FirstComment"});

            if (topicWithComments.Comments.Count > 0)
            {
                topicWithComments.Topic =  topicWithComments.Comments[0].Topic;
            }
            else
            {
                topicWithComments.Topic = Get(topicId);
            }

            return topicWithComments;
        }

        public TopicWithCommentsClient ToTopicWithCommentsClient(TopicWithComments topicWithComments)
        {

            TopicWithCommentsClient topicWithCommentsClient = new TopicWithCommentsClient();
            topicWithCommentsClient.PageComments = new PageListClient<CommentClientModel>(topicWithComments.Comments);

            foreach (var comment in topicWithComments.Comments)
            {
                topicWithCommentsClient.PageComments.Models.Add(_commentDriver.ToClient(comment));
            }
            topicWithCommentsClient.Topic = ToClient(topicWithComments.Topic, excludeProperties: new string[]{"Comments"});

            return topicWithCommentsClient;
        }
             
        public PageListClient<CommentClientModel> GetPageComments(Guid topicId, int pageIndex, int pageSize)
        {
            if (topicId == Guid.Empty) return null;
            Expression<Func<ContentComment, bool>> predicate = x => x.TopicId == topicId;
            var comments = _commentService.Paging(pageIndex, pageSize, "CreateTime desc", predicate);

            PageListClient<CommentClientModel> pageComments = new PageListClient<CommentClientModel>(comments);
            pageComments.Models = new List<CommentClientModel>();
            foreach (var comment in comments)
            {
                pageComments.Add(_commentDriver.ToClient(comment));
            }

            return pageComments;
        }
        
    }
}